add_parens <- function(x, digits = 2) {
  x <- as.numeric(x)
  return(paste0("(", sprintf(paste0("%.", digits, "f"), x), ")"))
}

format_num <- function(x, digits = 2) {
  x <- as.numeric(x)
  return(paste0(sprintf(paste0("%.", digits, "f"), x)))
}


make_entry <- function(est, se, p, digits = 2) {
  entry <- paste0(format_num(est, digits = digits), " ", 
                  add_parens(se, digits = digits))
  entry[p < 0.05] <- paste0(entry[p < 0.05], "*")
  return(entry)
}

table_entry <- function(est, se, digits = 2) {
  entry <- paste0(format_num(est, digits = digits), " ", 
                  add_parens(se, digits = digits))
  return(entry)
}

binomial_smooth <- function(...) {
  geom_smooth(method = "glm", method.args = list(family = "binomial"), ...)
}


glass_delta <- function(Y, Z, reference){
  Y/sd(Y[Z == reference], na.rm = TRUE)
}

## matStand and icwIndex from Cyrus: 
## https://github.com/cdsamii/make_index/blob/master/r/index_comparison.R


# Function to standardize columns of a matrix
# where you designate a standardization group
# (e.g., the control group in an experiment)
# with "sgroup", a logical vector.
matStand <- function(x, sgroup = rep(TRUE, nrow(x))){
  for(j in 1:ncol(x)){
    x[,j] <- (x[,j] - mean(x[sgroup,j]))/sd(x[sgroup,j])
  }
  return(x)
}

# Function that takes in data in matrix format and returns
# (i) IC weights and (ii) ICW index.
# Weights can be incorporated using the "wgts" argument.
# The "revcols" argument takes a vector indicating which columns,
# if any, should have values reversed (that is, standardized 
# values are multiplied by -1) prior to construction of the index. 
icwIndex <- function(	xmat,
                      wgts=rep(1, nrow(xmat)),
                      revcols = NULL,
                      sgroup = rep(TRUE, nrow(xmat))){
  X <- matStand(xmat, sgroup)
  if(length(revcols)>0){
    X[,revcols] <-  -1*X[,revcols]
  }
  i.vec <- as.matrix(rep(1,ncol(xmat)))
  Sx <- cov.wt(X, wt=wgts)[[1]]
  weights <- solve(t(i.vec)%*%solve(Sx)%*%i.vec)%*%t(i.vec)%*%solve(Sx)
  index <- t(solve(t(i.vec)%*%solve(Sx)%*%i.vec)%*%t(i.vec)%*%solve(Sx)%*%t(X))
  return(list(weights = weights, index = index))
}


## Function to make inverse covariance weighted indices
invcov <-
  function(Z, outcome_mat, to_reorient, reorient = FALSE) {
    if (length(Z) != nrow(outcome_mat))
      stop("Error: Treatment assignment, outcome matrix require same n!")
    if (reorient == TRUE) {
      outcome_mat[, c(to_reorient)] <- -outcome_mat[, c(to_reorient)]
    }
    c_mean <-
      apply(
        X = outcome_mat[Z == 0, ],
        MARGIN = 2,
        FUN = mean,
        na.rm = T
      )
    c_sd <-
      apply(
        X = outcome_mat[Z == 0, ],
        MARGIN = 2,
        FUN = sd,
        na.rm = T
      )
    z_score <- t(t(sweep(outcome_mat, 2, c_mean)) / c_sd)
    Sigma_hat <-
      solve(cov(z_score, y = z_score, use = "complete.obs"))
    one_vec <- as.vector(rep(1, ncol(outcome_mat)))
    if (sum(is.na(outcome_mat)) > 0) {
      z_score[is.na(z_score)] <- 0
    }
    w_ij <-
      t(solve(t(one_vec) %*% Sigma_hat %*% one_vec) %*% (t(one_vec) %*% Sigma_hat))
    if (sum(w_ij < 0) > 0) {
      warning('Warning, at least one weight is negative!')
    }
    s_ij <-
      t(solve(t(one_vec) %*% Sigma_hat %*% one_vec) %*% (t(one_vec) %*% Sigma_hat %*% t(z_score)))
    index <-
      (s_ij - mean(s_ij[Z == 0], na.rm = T)) / sd(s_ij[Z == 0], na.rm = T)
    return(s_ij)
  }


phone_clean <- function(phone, invalid = NA)
{
  phone <- gsub("[[:punct:]]", "", phone)          # remove punctuation
  phone <- trimws(phone)                           # remove whitespace
  phone[!nchar(phone) %in% c(7, 10)] <- invalid    # keep only 7 or 10 digit numbers
  phone[nchar(phone) %in% 7] <- gsub("(^\\d{3})(\\d{4}$)", 
                                     "\\1-\\2", 
                                     phone[nchar(phone) %in% 7])
  phone[nchar(phone) %in% 10] <- gsub("(^\\d{3})(\\d{3})(\\d{4}$)", 
                                      "\\1-\\2-\\3",
                                      phone[nchar(phone) %in% 10])
  phone <- gsub("-", "", phone)
  phone
}


freq_clean <-
  function(x) {
    factor(
      x,
      levels = c(
        "Never",
        "Some of the time",
        "About half the time",
        "Most of the time",
        "Always"
      )
    )
  }

freq_clean2 <-
  function(x) {
    factor(
      x,
      levels = c(
        "Never",
        "Sometimes",
        "About half the time",
        "Most of the time",
        "Always"
      )
    )
  }

gallup_clean <-
  function(x) {
    factor(
      x,
      levels = c(
        "None",
        "Very little",
        "Some",
        "Quite a lot",
        "A great deal"
        )
      )
  }


support_clean <-
  function(x) {
    factor(
      x,
      levels = c(
        "Strongly oppose",
        "Oppose",
        "Somewhat oppose",
        "Neither support nor oppose",
        "Somewhat support",
        "Support",
        "Strongly support"
      )
    )
  }

likely_clean <-
  function(x) {
    factor(
      x,
      levels = c(
        "Extremely unlikely",
        "Moderately unlikely",
        "Slightly unlikely",
        "Neither likely nor unlikely",
        "Slightly likely",
        "Moderately likely",
        "Extremely likely"
      )
    )
  }


agree_clean <-
  function(x) {
    factor(
      x,
      levels = c(
        "Strongly disagree",
        "Disagree",
        "Somewhat disagree",
        "Neither agree nor disagree",
        "Somewhat agree",
        "Agree",
        "Strongly agree"
      )
    )
  }